#!/usr/bin/env python3
"""
Phase 4A — 45s Pilot 渲染脚本
渲染新增的 Scene 03 和 Scene 05，合成 5 个 scene clips
"""

import os, sys, time, subprocess
from playwright.sync_api import sync_playwright

ROOT = r"E:\集群文件夹\factory_os\short_video_real_data_pipeline\phase4a_45s_pilot"
HTML_DIR = os.path.join(ROOT, "01_html_scenes")
FRAMES_DIR = os.path.join(ROOT, "02_frames")
CLIPS_DIR = os.path.join(ROOT, "03_scene_clips")

WIDTH, HEIGHT = 1080, 1920

NEW_SCENES = [
    {"name": "scene_03_candidates", "html": "scene_03_candidates.html", "duration": 10.0, "fps": 15},
    {"name": "scene_05_cta",        "html": "scene_05_cta.html",        "duration": 7.0,  "fps": 15},
]

def ensure_dirs():
    for d in [FRAMES_DIR, CLIPS_DIR]:
        os.makedirs(d, exist_ok=True)

def render_scene(scene):
    name = scene["name"]
    html = scene["html"]
    dur  = scene["duration"]
    fps  = scene["fps"]
    total = int(dur * fps)
    interval = 1.0 / fps

    html_path = os.path.join(HTML_DIR, html)
    out_dir = os.path.join(FRAMES_DIR, name)
    os.makedirs(out_dir, exist_ok=True)

    # Clean old frames
    for f in os.listdir(out_dir):
        if f.endswith(".png"):
            os.remove(os.path.join(out_dir, f))

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page(viewport={"width": WIDTH, "height": HEIGHT})
        file_url = "file:///" + html_path.replace("\\", "/")
        page.goto(file_url, wait_until="networkidle")
        time.sleep(0.3)

        print(f"  [渲染] {name}: {total} 帧 ({dur}s @ {fps}fps)")
        start = time.time()

        for i in range(total):
            target_ts = i * interval
            while True:
                elapsed = time.time() - start
                if elapsed >= target_ts:
                    break
                remaining = target_ts - elapsed
                if remaining > 0.005:
                    time.sleep(remaining * 0.8)

            fpath = os.path.join(out_dir, f"frame_{i:05d}.png")
            page.screenshot(path=fpath)

            if (i+1) % 30 == 0 or i == total-1:
                print(f"    {i+1}/{total}")

        elapsed = time.time() - start
        print(f"  [完成] {total} 帧, {elapsed:.1f}s")
        browser.close()

def compose_clip(name, fps, duration):
    frames_dir = os.path.join(FRAMES_DIR, name)
    output = os.path.join(CLIPS_DIR, f"{name}.mp4")

    if not os.path.isdir(frames_dir):
        print(f"  [跳过] 无帧目录: {frames_dir}")
        return False

    png_files = [f for f in os.listdir(frames_dir) if f.endswith(".png")]
    if not png_files:
        print(f"  [跳过] 无帧文件: {frames_dir}")
        return False

    pattern = os.path.join(frames_dir, "frame_%05d.png").replace("\\", "/")
    cmd = [
        "ffmpeg", "-y",
        "-framerate", str(fps),
        "-i", pattern,
        "-c:v", "libx264",
        "-pix_fmt", "yuv420p",
        "-preset", "medium",
        "-crf", "18",
        "-vf", f"scale={WIDTH}:{HEIGHT}:flags=lanczos",
        "-an", output,
    ]
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
    if result.returncode == 0:
        size = os.path.getsize(output) / (1024*1024)
        print(f"  [合成] {name}.mp4 ({size:.1f} MB)")
        return True
    else:
        print(f"  [错误] FFmpeg: {result.stderr[-200:]}")
        return False

def main():
    ensure_dirs()

    print("=== 渲染新增 Scene ===")
    for scene in NEW_SCENES:
        print(f"\n▶ {scene['name']}")
        render_scene(scene)

    print("\n=== 合成新增 Clip ===")
    for scene in NEW_SCENES:
        compose_clip(scene["name"], scene["fps"], scene["duration"])

    print("\n✅ Phase 4A 渲染完成")
    return 0

if __name__ == "__main__":
    sys.exit(main())
